from optparse import OptionParser
import logging
from ConfigParser import ConfigParser
import redis
import python_library.utils as utils

class ErrorReportor(object):
  def __init__(self, config_fname):
    self._load_config(config_fname)
    self._redis_cli = redis.StrictRedis(**self._redis_config)

  def _load_config(self, config_fname):
    parser = ConfigParser()
    parser.read(config_fname)
    self._redis_config = {}
    for option in parser.options('redis'):
      self._redis_config[option] = parser.get('redis', option)
    procedures = parser.get('base', 'procedures').split('|')
    self._procedures = {}
    for procedure in procedures:
      self._procedures[procedure] = {}
      self._procedures[procedure]['redis_key'] = parser.get(procedure, 'key')
      self._procedures[procedure]['max_count'] = int(parser.get(procedure, 'maxcount'))
      self._procedures[procedure]['receiver']  = parser.get(procedure, 'receiver')
      self._procedures[procedure]['mailtitle']  = parser.get(procedure, 'mailtitle')

  def Run(self):
    for proc, item in self._procedures.items():
      report_text = self._fetch_data(item['redis_key'], item['max_count'])
      utils.SendMail(item['mailtitle'], report_text, item['receiver'])

  def _fetch_data(self, redis_key, max_count):
    site_to_count      = {}
    exception_to_count = {}
    site_to_info       = {}
    total              = 0

    for i in range(max_count):
      item = self._fetch_one(redis_key)
      if item:
        try:
          temp = eval(item)
        except Exception, e:
          continue
        else:
          source = temp.get('source', '')
          id  = temp.get('id', '')
          err = temp.get('err', '')
          if len(source) == 0 or len(err) == 0 or len(id) == 0:
            logging.error('inappropriate error message found : %s'%item)
            continue
        if source not in site_to_info.keys():
          site_to_info[source] = {}
        if err not in site_to_info[source]:
          site_to_info[source][err] = []
        site_to_info[source][err].append(id)
    for source in site_to_info.keys():
      if source not in site_to_count.keys():
        site_to_count[source] = 0
      for err in site_to_info[source]:
        if err not in exception_to_count.keys():
          exception_to_count[err] = 0
        site_to_count[source] += len(site_to_info[source][err])
        exception_to_count[err] += len(site_to_info[source][err])
        total += len(site_to_info[source][err])

    print site_to_count
    print exception_to_count
    print total
    return self._gen_html(total, site_to_count, exception_to_count, site_to_info)

  def _fetch_one(self, redis_key):
    try:
      result = self._redis_cli.spop(redis_key)
    except Exception, e:
      logging.error('failed to retrieve message reason : %s' % e)
      return None
    else:
      return result

  def _format_statistic_table(self, total, site_to_count, exception_to_count, site_to_info):
    report_text = '<table border="1">\n<tr><th>   </th>'
    for err in exception_to_count.keys():
      report_text = report_text + '<th bgcolor="yellow">' + err + '</th>'
    report_text = report_text + '<th bgcolor="yellow">total</th></tr>'
    for site, info in site_to_info.items():
      report_text = report_text + '<tr><th>' + site + '</th>'
      for err in exception_to_count.keys():
        ids = site_to_info[site].get(err, [])
        report_text += '<th><ul>'
        for i in range(5):
          if i >= len(ids):
            break
          report_text = report_text + '<li>' + ids[i] + '</li>'
        report_text += '</ul>'
        sum = info.get(err, [])
        if len(sum) != 0:
          report_text += 'sum : <span bgcolor="red">' + str(len(sum)) + '<span></th>'
      report_text = report_text + '<th>' + str(site_to_count[site]) + '</th></tr>'
    report_text = report_text + '<tr><th>total</th>'
    for err in exception_to_count.keys():
      report_text = report_text + '<th>' + str(exception_to_count[err]) + '</th>'
    report_text = report_text + '<th>' + str(total) + '</th><tr></table>'
    return report_text

  def _gen_html(self, total, site_to_count, exception_to_count, site_to_info):
    report_text = '''
    <html><body>
      total        : %d<br><br>
    '''    % total
    report_text += self._format_statistic_table(total, site_to_count, exception_to_count, site_to_info)
    report_text += '<br><hr><br>'

    report_text += '<table border = "1">'
    for source, info in site_to_info.items():
      for err, ids in info.items():
        for id in sorted(ids, utils._cmp):
          row = "<tr><th>" + source + "</th><th>" + err + "</th><th>" + str(id) + "</th></tr>"
          report_text += row

    report_text += "</table>"
    report_text += "</body></html>"
    return report_text

def main(config_fname, args):
  reportor =  ErrorReportor(config_fname)
  reportor.Run()

if __name__ == "__main__":
  logging.basicConfig(level=logging.DEBUG,
                      format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
                      datefmt='%a, %d %b %Y %H:%M:%S',
                      filename='error_reportor.log',
                      filemode='w')

  parser = OptionParser()
  parser.add_option("-c", "--config", dest = "config_fname", default="config/error_report.config",
                    help = "config file name")
  (options, args) = parser.parse_args()
  main(options.config_fname, args)
